package fr.upec.tisdtr.indoorlocation.hardware;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.Context;
import android.net.ConnectivityManager;
import android.os.Build;
import android.telephony.TelephonyManager;
import android.util.Log;

public class MobileDataManager {
	
	private static final String TAG = "MobileDataManager";
	
	/**
	 * Switch mobile connection (PDP state)
	 */
	public static void setMobileDataEnabled(Context context, boolean enabled) {
		
		if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
			Log.d(TAG, "setMobileDataEnabled: 4.4");
			setMobileDataEnabledOnVersionKitKat(context, enabled);
			
		} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) {
			Log.d(TAG, "setMobileDataEnabled: 2.2+ (excluding 2.2)");
			setMobileDataEnabledOnVersionAfterFroyo(context, enabled);
			
		} else {
			Log.d(TAG, "setMobileDataEnabled: 2.2- (including 2.2)");
			setMobileDataEnabledOnVersionUnderFroyo(context, enabled);
		}
	}
	
	/**
	 * For Android version from 4.4 and following, use this method.
	 * It's a joke.
	 * @param context
	 * @param enabled
	 */
	private static void setMobileDataEnabledOnVersionKitKat(Context context, boolean enabled) {// 4.4
		Log.v(TAG, "setMobileDataEnabledOnVersionKitKat: enabled=" + enabled);
		ConnectivityManager connectivitymanager = (ConnectivityManager)context.getSystemService("connectivity");
		try {
			Class<?> class1 = connectivitymanager.getClass();
			Class<?> aclass[] = new Class[1];
			aclass[0] = Boolean.TYPE;
			Method method = class1.getMethod("setMobileDataEnabled", aclass);
			Object aobj[] = new Object[1];
			aobj[0] = Boolean.valueOf(enabled);
			method.invoke(connectivitymanager, aobj);
			return;
			
		} catch (SecurityException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: SecurityException error : ", e);
		} catch (IllegalArgumentException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: IllegalArgumentException error : ", e);
		} catch (IllegalAccessException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: IllegalAccessException error : ", e);
		} catch (NoSuchMethodException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: NoSuchMethodException error : ", e);
		} catch (InvocationTargetException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: InvocationTargetException error : ", e);
		}
	}


	/**
	 * For Android version from 2.2.1 and following, use this method.
	 * It's a projection of setMobileDataEnabled method from ConnectivityManager API.
	 * @param context
	 * @param enabled
	 */
	private static void setMobileDataEnabledOnVersionAfterFroyo(Context context, boolean enabled) {// 2.2.1+
		Log.v(TAG, "setMobileDataEnabledOnVersionAfterFroyo: enabled=" + enabled);
		try {
			ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
			Class<?> connectivityClass = Class.forName(connectivity.getClass().getName());
			Field iConnectivityManagerField = connectivityClass.getDeclaredField("mService");
			iConnectivityManagerField.setAccessible(true);
			Object iConnectivityManager = iConnectivityManagerField.get(connectivity);
			Class<?> iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
			Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
			setMobileDataEnabledMethod.setAccessible(true);
			setMobileDataEnabledMethod.invoke(iConnectivityManager, Boolean.valueOf(enabled));
			
		} catch (ClassNotFoundException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: ClassNotFoundException error : ", e);
		} catch (SecurityException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: SecurityException error : ", e);
		} catch (NoSuchFieldException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: NoSuchFieldException error : ", e);
		} catch (IllegalArgumentException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: IllegalArgumentException error : ", e);
		} catch (IllegalAccessException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: IllegalAccessException error : ", e);
		} catch (NoSuchMethodException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: NoSuchMethodException error : ", e);
		} catch (InvocationTargetException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionAfterFroyo: InvocationTargetException error : ", e);
		}
	}

	/**
	 * For Android version 2.2 and previous, use this method.
	 * It's a projection of getITelephony method from TelephonyManager API.
	 * @param context
	 * @param enabled
	 */
	private static void setMobileDataEnabledOnVersionUnderFroyo(Context context, boolean enabled) {// 2.2-
		Log.v(TAG, "setMobileDataEnabledOnVersionUnderFroyo: enabled=" + enabled);
		Method dataConnectionSwitchMethod;
		Class<?> telephonyManagerClass;
		Object iTelephonyStub;
		Class<?> iTelephonyClass;
		try {
			TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
			telephonyManagerClass = Class.forName(telephonyManager.getClass().getName());
			Method getITelephonyMethod = telephonyManagerClass.getDeclaredMethod("getITelephony");
			getITelephonyMethod.setAccessible(true);
			iTelephonyStub = getITelephonyMethod.invoke(telephonyManager);
			iTelephonyClass = Class.forName(iTelephonyStub.getClass().getName());

			if (!enabled) {
				dataConnectionSwitchMethod = iTelephonyClass.getDeclaredMethod("disableDataConnectivity");
			} else {
				dataConnectionSwitchMethod = iTelephonyClass.getDeclaredMethod("enableDataConnectivity");
			}
			dataConnectionSwitchMethod.setAccessible(true);
			dataConnectionSwitchMethod.invoke(iTelephonyStub);

		} catch (ClassNotFoundException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionUnderFroyo: ClassNotFoundException error : ", e);
		} catch (SecurityException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionUnderFroyo: SecurityException error : ", e);
		} catch (NoSuchMethodException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionUnderFroyo: NoSuchMethodException error : ", e);
		} catch (IllegalArgumentException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionUnderFroyo: IllegalArgumentException error : ", e);
		} catch (IllegalAccessException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionUnderFroyo: IllegalAccessException error : ", e);
		} catch (InvocationTargetException e) {
			Log.e(TAG, "setMobileDataEnabledOnVersionUnderFroyo: InvocationTargetException error : ", e);
		}
	}


}